home *** CD-ROM | disk | FTP | other *** search
- ;;
- ;; aPLib compression library - the smaller the better :)
- ;;
- ;; NASM 16bit assembler tiny depacker example
- ;;
- ;; Copyright (c) 1998-2000 by Joergen Ibsen / Jibz
- ;; All Rights Reserved
- ;;
- ;; -> 16bit by METALBRAIN (metalb@bart.us.es)
- ;;
-
- org 256
-
- cld ;Clear direction flag for safety
- mov ah,4ah ;Modify memory block size (on start,
- ; the .COM program is given all free
- ; memory, but this could be less than
- ; the needed amount (162K). As a nice
- ; side effect, we are freeing unused
- ; memory, but who cares under DOS?
- mov bh,41 ;Number of needed paragraphs
- ; (rounded up)
- call int_n_check ;Resize or exit if error
-
- mov si,129 ;Arguments from PSP start here
- mov di,testitnow ;This will be called quite a few times
- ; and later will be used to place
- ; variables
- space1 call di ;Parse...
- jz space1 ;Search for non-space
- dec si ;Found: here start infile name
- mov dx,si ;Keep it in DX
- space2 call di ;Keep parsing
- jnz space2 ;Till a space appears
- mov [si-1],dh ;Make infile ASCIIZ
- space3 call di
- jz space3 ;Now search a non-space again
- dec si ;Here start outfile name
- push si ;Keep it in stack
- space4 lodsb ;Final parse
- cmp al," "
- ja space4 ;Space or below means end of filename
- mov [si-1],dh ;Make ASCIIZ this one too
- mov ax,3d00h ;Function to open infile
- call int_n_check ;Try it
- stosw ;Store infile handle at handlein
- mov dx,tmpname
- xor cx,cx
- mov ah,3ch
- call int_n_check ;Create temporal outfile: "NOT OK$"
- stosw ;Store temporal outfile handle
- xchg ax,dx ;And place it in DX
- xor ebx,ebx ;EBX=0
- pop si ;Pop outfile name address from stack
- mov bh,8 ;BX=inbuff
- mov esp,ebx ;Set stack before inbuff
- mov bx,es ;Segment
- add bh,8 ; +32K
- imul eax,ebx,byte 16 ;32 bit start of segment address+32K
- add eax,esp ;EAX=freemem 32 bit address
- push si ;Push again outfile name address
- push dx ;Also store temporal outfile handle
- mov dl,128 ;Reset bit counter in DL, and DX=0080h
- mov cl,3 ;Set EAX at freemem32, origin32 and
- rep stosd ; limit32
- add [di-2],byte 2 ;Now limit32=freemem32+128K
- add [di-7],dx ;Now origin32=freemem32+32K
- xchg eax,edi ;Set freemem32 at EDI
- mov esi,edi ;And ESI
- ;Starting point for DEPACK16
- push edi ;Store freemem32
- literal call getesi ;Copy a byte from [esi] to [edi]
- putedi_nexttag call putedi
- call newtest ;Here EAX=0
- jmp short nexttag ;Skip next part
-
- normalcodepair xchg ax,cx ;High part of distance in AX
- dec ax ;Subtract 1. Min value is 0
- shl eax,8 ;EAX=00dddd00h
- call getesi ;Fill distance in AL
- call getgamma ;Take gamma encoded ECX
- cmp eax,32000
- jae domatch_with_2inc ;Above 31999: ECX+=2
- cmp ah,5
- jae domatch_with_inc ; 1279<EAX<32000: ECX=+1
- cmp ax,byte 127
- ja domatch ;EAX<128: ECX+=2
- domatch_with_2inc
- inc ecx
- domatch_with_inc
- inc ecx
- domatch xchg eax,ebp ;Store EAX in EBP
- domatch_R0 mov eax,ebp ;Take EAX from last EBP
- domatch_continue
- ;Here EAX=match distance
- ; ECX=match lenght
- push esi ;Store current read pointer
- mov esi,edi
- sub esi,eax ;ESI=EDI-EAX > origin pointer
- cmp esi,[freemem32] ;Test for bad infile #1: Limit crossed
- call finerr01 ;Exit if error
- repmovsb call dontread ;getesi without checking limit
- call putedi ;and with putedi completes the movsb
- mov ah,128 ;Here EAX=32768 (in case of writing
- call newtest ; data, update esi too)
- loop repmovsb,ecx ;Do it ecx times
- pop esi ;Recover read pointer
- nexttag call getbit ;Get a bit
- jnc literal ;0: literal, go for it
- xor ecx,ecx ;Clear ECX
- xor ax,ax ;and AX
- call getbit ;Get another bit
- jnc codepair ;10: codepair, go for it
- call getbit ;Get yet another one
- jnc shortmatch ;110: shortmatch
- mov al,16 ;Set marker bit
- inc cx ;CX=1
- getmorebits call getbit ;Get a bit
- adc al,al ;Set it in AL
- jnc getmorebits ;Do it till marker is out (4 times)
- jnz domatch_continue ; 111xxxx > continue, AL has distance
- jmp short putedi_nexttag ;1110000: Put a zero byte
-
- codepair call getgamma ;Get gamma encoded first part of
- ; distance in CX. Min value is 2
- dec cx ;\Subtract 2, if not zero then
- loop normalcodepair ;/continue with distance
- push word domatch_R0 ;Get gamma encoded lenght in ECX then
- ; jump to domatch_R0 (use last
- ; distance)
-
- getgamma inc cx ;First bit is always 1
- getgammaloop call getbit ;Get next bit
- adc ecx,ecx ;Put it in ECX
- call getbit ;Get gamma bit
- jc getgammaloop ;If it's 1, continue growing ECX
- ret
-
- shortmatch call getesi ;Get a byte
- shr ax,1 ;Distance = AL/2, Lenght in carry flag
- jz donedepacking ;If zero, end packing
- adc cx,cx ;Lenght = 1 or 0
- jmp short domatch_with_2inc ; Decode with lenght 2 or 3
-
- donedepacking pop esi ;ESI=freemem32
- pop bx ;Get outfile handle
- sub edi,esi ;And here finish DEPACK 16
- ;Now edi has the number of depacked
- ; bytes left to be written
- push ds ;Preserve data segment
- mov ch,080h ;Write using 32K chunks to enable
- ; the sign optimization
- mov dx,freemem ;Flush everything from here to end
- more cmp edi,ecx
- ja notlast ;If EDI > 32K, write 32K bytes
- mov cx,di ;If EDI < 32K, write EDI bytes
- notlast call writefile ;Write chunk
- mov ax,ds
- add ah,8
- mov ds,ax ;Advance 32K
-
- sub edi,ecx ;Update number of bytes to be written
- ja more ;Above zero, continue writing
- pop ds ;Recover data segment
- push ds
- pop es ;Set es=ds
- pop dx ;Get pointer to outfile name
- call close_del ;Close temporal outfile and try to
- ; delete the file named with our
- ; outfile name, in case it exists
- jnc renameit ;If that file existed and was deleted,
- ; go ahead and rename the temporal one
- cmp al,5 ;If it didn't exist, rename it too
- jz finerr ;But if error was for other reason,
- ; exit with NOT OK
- renameit mov ah,56h
- mov di,dx
- mov dx,tmpname
- call int_n_check ;Rename temporal outfile to outfile
- mov dx,noerr ;Final message: OK
- final_dxok mov ah,9
- int 33 ;Show final message
- int 20h ;Exit program
-
- writefile mov ah,40h
- call int_n_check ;Write
- dec ax
- jns not_finerr ;If disk isn't full there's no error
- finerr mov dx,tmpname ;Error message: NOT OK
- push word final_dxok ;Return point
- close_del mov ah,3eh
- int 33 ;Close temporal outfile
- mov ah,41h
- int 33 ;Delete outfile (when called to
- ; close_del) or temporal outfile
- not_finerr ret ; (when we fall from finerr)
-
- getesi cmp esi,[freemem32] ; If esi is at freemem32, we must
- jnz dontread ;load 32k of compressed data
- pushad ;Keep all registers (32bit because
- mov ah,3fh ; DOS function may modify EAX!!!)
- mov bx,[handlein] ;Take infile handle
- mov cx,32768 ;Number of bytes
- mov dx,inbuff ;Place to read
- call int_n_check ;Read and exit if error
- dec ax ;---Test for bad infile #2: 0 bytes
- popad ;\/ read (a good infile will finish
- js finerr ;/\ and won't ask for more data)
- ; >Restore registers
- sub esi,32768 ;esi at beginning of buffer again
- dontread push esi ;----->Emulates mov al,[esi] in 16 bit
- pop bx ; / code (as mov al,[esi] gives
- pop bx ; / a nasty fault)
- ror bx,4 ; /
- mov es,bx ; /
- mov al,[es:si] ;/
- inc esi ;Update read pointer
- ret
-
- int_n_check int 33 ;Perform operation (depends on AH)
- finerr01 jc finerr ;If it failed, exit with NOT OK
- ret
-
- getbit add dl,dl ;Get a tag bit
- jnz stillbitsleft ;If zero, that bit was the marker, so
- ; we must read a new tag byte from
- xchg ax,dx ;\ the infile buffer
- call getesi ; >Emulate mov dl,[esi], inc esi
- xchg ax,dx ;/
- stc ;Carry flag is end marker
- adc dl,dl ;Get first bit and set marker
- stillbitsleft ret ;Return with bit read in flag C
-
- newtest cmp edi,[limit32] ;Check if we've run out of memory
- jc endtest ;NO: end test
- pushad ;Keep registers
- mov dx,freemem
- mov cx,32768
- mov bx,[handletmp]
- call writefile ;Write 32K of data
- mov ecx,edi
- mov esi,[origin32]
- sub ecx,esi ;ECX=number of bytes to be moved
- mov edi,[freemem32] ;Output data will be moved 32K back
- otherrepmovsb call getesi ; \
- call putedi ; >Emulates rep movsb
- loop otherrepmovsb,ecx ;/
- popad ;Restore registers
- sub esi,eax ;Update read pointer (sub 32K if
- ; we are in the repmovsb loop)
- mov ah,128 ;EAX=32K
- sub edi,eax ;Update write pointer
- endtest ret
-
- putedi push edi ;----->Emulate mov [edi],al in 16 bit
- pop bx ; / code (as mov [edi],al gives
- pop bx ; / a nasty fault)
- ror bx,4 ; /
- mov es,bx ; /
- mov [es:di],al ;/
- inc edi ;Update write pointer
- xor eax,eax ;Clear EAX
- ret
-
- tmpname db "NOT "
- noerr db "OK$",0
-
- testitnow lodsb ;Parse one byte
- cmp al,32 ;Is it space?
- jc finerr01 ;Below space: bad arguments > exit
- ret
-
- handlein EQU testitnow
- handletmp EQU testitnow+2
- freemem32 EQU testitnow+4
- origin32 EQU testitnow+8
- limit32 EQU testitnow+12
- ;Stack is between program and 1280
- inbuff EQU 2048 ;Place for 32K infile reading buffer
- freemem EQU inbuff+32768
-